home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / Mail / names.c < prev    next >
C/C++ Source or Header  |  1990-02-08  |  13KB  |  659 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. #ifndef lint
  19. static char sccsid[] = "@(#)names.c    5.13 (Berkeley) 7/8/88";
  20. #endif /* not lint */
  21.  
  22. /*
  23.  * Mail -- a mail program
  24.  *
  25.  * Handle name lists.
  26.  */
  27.  
  28. #include "rcv.h"
  29.  
  30. /*
  31.  * Allocate a single element of a name list,
  32.  * initialize its name field to the passed
  33.  * name and return it.
  34.  */
  35. struct name *
  36. nalloc(str, ntype)
  37.     char str[];
  38. {
  39.     register struct name *np;
  40.  
  41.     np = (struct name *) salloc(sizeof *np);
  42.     np->n_flink = NIL;
  43.     np->n_blink = NIL;
  44.     np->n_type = ntype;
  45.     np->n_name = savestr(str);
  46.     return(np);
  47. }
  48.  
  49. /*
  50.  * Find the tail of a list and return it.
  51.  */
  52. struct name *
  53. tailof(name)
  54.     struct name *name;
  55. {
  56.     register struct name *np;
  57.  
  58.     np = name;
  59.     if (np == NIL)
  60.         return(NIL);
  61.     while (np->n_flink != NIL)
  62.         np = np->n_flink;
  63.     return(np);
  64. }
  65.  
  66. /*
  67.  * Extract a list of names from a line,
  68.  * and make a list of names from it.
  69.  * Return the list or NIL if none found.
  70.  */
  71. struct name *
  72. extract(line, ntype)
  73.     char line[];
  74. {
  75.     register char *cp;
  76.     register struct name *top, *np, *t;
  77.     char nbuf[BUFSIZ];
  78.  
  79.     if (line == NOSTR || *line == '\0')
  80.         return NIL;
  81.     top = NIL;
  82.     np = NIL;
  83.     cp = line;
  84.     while ((cp = yankword(cp, nbuf)) != NOSTR) {
  85.         t = nalloc(nbuf, ntype);
  86.         if (top == NIL)
  87.             top = t;
  88.         else
  89.             np->n_flink = t;
  90.         t->n_blink = np;
  91.         np = t;
  92.     }
  93.     return top;
  94. }
  95.  
  96. /*
  97.  * Turn a list of names into a string of the same names.
  98.  */
  99. char *
  100. detract(np, ntype)
  101.     register struct name *np;
  102. {
  103.     register int s;
  104.     register char *cp, *top;
  105.     register struct name *p;
  106.     register int comma;
  107.  
  108.     comma = ntype & GCOMMA;
  109.     if (np == NIL)
  110.         return(NOSTR);
  111.     ntype &= ~GCOMMA;
  112.     s = 0;
  113.     if (debug && comma)
  114.         fprintf(stderr, "detract asked to insert commas\n");
  115.     for (p = np; p != NIL; p = p->n_flink) {
  116.         if (ntype && (p->n_type & GMASK) != ntype)
  117.             continue;
  118.         s += strlen(p->n_name) + 1;
  119.         if (comma)
  120.             s++;
  121.     }
  122.     if (s == 0)
  123.         return(NOSTR);
  124.     s += 2;
  125.     top = salloc(s);
  126.     cp = top;
  127.     for (p = np; p != NIL; p = p->n_flink) {
  128.         if (ntype && (p->n_type & GMASK) != ntype)
  129.             continue;
  130.         cp = copy(p->n_name, cp);
  131.         if (comma && p->n_flink != NIL)
  132.             *cp++ = ',';
  133.         *cp++ = ' ';
  134.     }
  135.     *--cp = 0;
  136.     if (comma && *--cp == ',')
  137.         *cp = 0;
  138.     return(top);
  139. }
  140.  
  141. /*
  142.  * Grab a single word (liberal word)
  143.  * Throw away things between ()'s, and take anything between <>.
  144.  */
  145. char *
  146. yankword(ap, wbuf)
  147.     char *ap, wbuf[];
  148. {
  149.     register char *cp, *cp2;
  150.  
  151.     cp = ap;
  152.     for (;;) {
  153.         if (*cp == '\0')
  154.             return NOSTR;
  155.         if (*cp == '(') {
  156.             register int nesting = 0;
  157.  
  158.             while (*cp != '\0') {
  159.                 switch (*cp++) {
  160.                 case '(':
  161.                     nesting++;
  162.                     break;
  163.                 case ')':
  164.                     --nesting;
  165.                     break;
  166.                 }
  167.                 if (nesting <= 0)
  168.                     break;
  169.             }
  170.         } else if (*cp == ' ' || *cp == '\t' || *cp == ',')
  171.             cp++;
  172.         else
  173.             break;
  174.     }
  175.     if (*cp ==  '<')
  176.         for (cp2 = wbuf; *cp && (*cp2++ = *cp++) != '>';)
  177.             ;
  178.     else
  179.         for (cp2 = wbuf; *cp && !index(" \t,(", *cp); *cp2++ = *cp++)
  180.             ;
  181.     *cp2 = '\0';
  182.     return cp;
  183. }
  184.  
  185. /*
  186.  * For each recipient in the passed name list with a /
  187.  * in the name, append the message to the end of the named file
  188.  * and remove him from the recipient list.
  189.  *
  190.  * Recipients whose name begins with | are piped through the given
  191.  * program and removed.
  192.  */
  193. struct name *
  194. outof(names, fo, hp)
  195.     struct name *names;
  196.     FILE *fo;
  197.     struct header *hp;
  198. {
  199.     register int c;
  200.     register struct name *np, *top;
  201.     time_t now, time();
  202.     char *date, *fname, *ctime();
  203.     FILE *fout, *fin;
  204.     int ispipe;
  205.     extern char tempEdit[];
  206.  
  207.     top = names;
  208.     np = names;
  209.     (void) time(&now);
  210.     date = ctime(&now);
  211.     while (np != NIL) {
  212.         if (!isfileaddr(np->n_name) && np->n_name[0] != '|') {
  213.             np = np->n_flink;
  214.             continue;
  215.         }
  216.         ispipe = np->n_name[0] == '|';
  217.         if (ispipe)
  218.             fname = np->n_name+1;
  219.         else
  220.             fname = expand(np->n_name);
  221.  
  222.         /*
  223.          * See if we have copied the complete message out yet.
  224.          * If not, do so.
  225.          */
  226.  
  227.         if (image < 0) {
  228.             if ((fout = fopen(tempEdit, "a")) == NULL) {
  229.                 perror(tempEdit);
  230.                 senderr++;
  231.                 goto cant;
  232.             }
  233.             image = open(tempEdit, 2);
  234.             (void) unlink(tempEdit);
  235.             if (image < 0) {
  236.                 perror(tempEdit);
  237.                 senderr++;
  238.                 goto cant;
  239.             }
  240.             else {
  241.                 fprintf(fout, "From %s %s", myname, date);
  242.                 puthead(hp, fout, GTO|GSUBJECT|GCC|GNL);
  243.                 while ((c = getc(fo)) != EOF)
  244.                     (void) putc(c, fout);
  245.                 rewind(fo);
  246.                 (void) putc('\n', fout);
  247.                 (void) fflush(fout);
  248.                 if (ferror(fout))
  249.                     perror(tempEdit);
  250.                 (void) fclose(fout);
  251.             }
  252.         }
  253.  
  254.         /*
  255.          * Now either copy "image" to the desired file
  256.          * or give it as the standard input to the desired
  257.          * program as appropriate.
  258.          */
  259.  
  260.         if (ispipe) {
  261.             int pid;
  262.             char *shell;
  263.  
  264.             /* XXX, can't really reuse the same image file */
  265.             if ((shell = value("SHELL")) == NOSTR)
  266.                 shell = SHELL;
  267.             pid = start_command(shell, sigmask(SIGHUP)|
  268.                     sigmask(SIGINT)|sigmask(SIGQUIT),
  269.                 image, -1, "-c", fname, NOSTR);
  270.             if (pid < 0) {
  271.                 senderr++;
  272.                 goto cant;
  273.             }
  274.             free_child(pid);
  275.         } else {
  276.             if ((fout = fopen(fname, "a")) == NULL) {
  277.                 perror(fname);
  278.                 senderr++;
  279.                 goto cant;
  280.             }
  281.             fin = Fdopen(image, "r");
  282.             if (fin == NULL) {
  283.                 fprintf(stderr, "Can't reopen image\n");
  284.                 (void) fclose(fout);
  285.                 senderr++;
  286.                 goto cant;
  287.             }
  288.             rewind(fin);
  289.             while ((c = getc(fin)) != EOF)
  290.                 (void) putc(c, fout);
  291.             if (ferror(fout))
  292.                 senderr++, perror(fname);
  293.             (void) fclose(fout);
  294.             (void) fclose(fin);
  295.         }
  296. cant:
  297.         /*
  298.          * In days of old we removed the entry from the
  299.          * the list; now for sake of header expansion
  300.          * we leave it in and mark it as deleted.
  301.          */
  302.         np->n_type |= GDEL;
  303.         np = np->n_flink;
  304.     }
  305.     if (image >= 0) {
  306.         (void) close(image);
  307.         image = -1;
  308.     }
  309.     return(top);
  310. }
  311.  
  312. /*
  313.  * Determine if the passed address is a local "send to file" address.
  314.  * If any of the network metacharacters precedes any slashes, it can't
  315.  * be a filename.  We cheat with .'s to allow path names like ./...
  316.  */
  317. isfileaddr(name)
  318.     char *name;
  319. {
  320.     register char *cp;
  321.  
  322.     if (*name == '+')
  323.         return 1;
  324.     for (cp = name; *cp; cp++) {
  325.         if (*cp == '!' || *cp == '%' || *cp == '@')
  326.             return 0;
  327.         if (*cp == '/')
  328.             return 1;
  329.     }
  330.     return 0;
  331. }
  332.  
  333. /*
  334.  * Map all of the aliased users in the invoker's mailrc
  335.  * file and insert them into the list.
  336.  * Changed after all these months of service to recursively
  337.  * expand names (2/14/80).
  338.  */
  339.  
  340. struct name *
  341. usermap(names)
  342.     struct name *names;
  343. {
  344.     register struct name *new, *np, *cp;
  345.     struct grouphead *gh;
  346.     register int metoo;
  347.  
  348.     new = NIL;
  349.     np = names;
  350.     metoo = (value("metoo") != NOSTR);
  351.     while (np != NIL) {
  352.         if (np->n_name[0] == '\\') {
  353.             cp = np->n_flink;
  354.             new = put(new, np);
  355.             np = cp;
  356.             continue;
  357.         }
  358.         gh = findgroup(np->n_name);
  359.         cp = np->n_flink;
  360.         if (gh != NOGRP)
  361.             new = gexpand(new, gh, metoo, np->n_type);
  362.         else
  363.             new = put(new, np);
  364.         np = cp;
  365.     }
  366.     return(new);
  367. }
  368.  
  369. /*
  370.  * Recursively expand a group name.  We limit the expansion to some
  371.  * fixed level to keep things from going haywire.
  372.  * Direct recursion is not expanded for convenience.
  373.  */
  374.  
  375. struct name *
  376. gexpand(nlist, gh, metoo, ntype)
  377.     struct name *nlist;
  378.     struct grouphead *gh;
  379. {
  380.     struct group *gp;
  381.     struct grouphead *ngh;
  382.     struct name *np;
  383.     static int depth;
  384.     char *cp;
  385.  
  386.     if (depth > MAXEXP) {
  387.         printf("Expanding alias to depth larger than %d\n", MAXEXP);
  388.         return(nlist);
  389.     }
  390.     depth++;
  391.     for (gp = gh->g_list; gp != NOGE; gp = gp->ge_link) {
  392.         cp = gp->ge_name;
  393.         if (*cp == '\\')
  394.             goto quote;
  395.         if (strcmp(cp, gh->g_name) == 0)
  396.             goto quote;
  397.         if ((ngh = findgroup(cp)) != NOGRP) {
  398.             nlist = gexpand(nlist, ngh, metoo, ntype);
  399.             continue;
  400.         }
  401. quote:
  402.         np = nalloc(cp, ntype);
  403.         /*
  404.          * At this point should allow to expand
  405.          * to self if only person in group
  406.          */
  407.         if (gp == gh->g_list && gp->ge_link == NOGE)
  408.             goto skip;
  409.         if (!metoo && strcmp(cp, myname) == 0)
  410.             np->n_type |= GDEL;
  411. skip:
  412.         nlist = put(nlist, np);
  413.     }
  414.     depth--;
  415.     return(nlist);
  416. }
  417.  
  418. /*
  419.  * Concatenate the two passed name lists, return the result.
  420.  */
  421. struct name *
  422. cat(n1, n2)
  423.     struct name *n1, *n2;
  424. {
  425.     register struct name *tail;
  426.  
  427.     if (n1 == NIL)
  428.         return(n2);
  429.     if (n2 == NIL)
  430.         return(n1);
  431.     tail = tailof(n1);
  432.     tail->n_flink = n2;
  433.     n2->n_blink = tail;
  434.     return(n1);
  435. }
  436.  
  437. /*
  438.  * Unpack the name list onto a vector of strings.
  439.  * Return an error if the name list won't fit.
  440.  */
  441. char **
  442. unpack(np)
  443.     struct name *np;
  444. {
  445.     register char **ap, **top;
  446.     register struct name *n;
  447.     int t, extra, metoo, verbose;
  448.  
  449.     n = np;
  450.     if ((t = count(n)) == 0)
  451.         panic("No names to unpack");
  452.     /*
  453.      * Compute the number of extra arguments we will need.
  454.      * We need at least two extra -- one for "mail" and one for
  455.      * the terminating 0 pointer.  Additional spots may be needed
  456.      * to pass along -f to the host mailer.
  457.      */
  458.     extra = 2;
  459.     extra++;
  460.     metoo = value("metoo") != NOSTR;
  461.     if (metoo)
  462.         extra++;
  463.     verbose = value("verbose") != NOSTR;
  464.     if (verbose)
  465.         extra++;
  466.     top = (char **) salloc((t + extra) * sizeof *top);
  467.     ap = top;
  468.     *ap++ = "send-mail";
  469.     *ap++ = "-i";
  470.     if (metoo)
  471.         *ap++ = "-m";
  472.     if (verbose)
  473.         *ap++ = "-v";
  474.     for (; n != NIL; n = n->n_flink)
  475.         if ((n->n_type & GDEL) == 0)
  476.             *ap++ = n->n_name;
  477.     *ap = NOSTR;
  478.     return(top);
  479. }
  480.  
  481. /*
  482.  * Remove all of the duplicates from the passed name list by
  483.  * insertion sorting them, then checking for dups.
  484.  * Return the head of the new list.
  485.  */
  486. struct name *
  487. elide(names)
  488.     struct name *names;
  489. {
  490.     register struct name *np, *t, *new;
  491.     struct name *x;
  492.  
  493.     if (names == NIL)
  494.         return(NIL);
  495.     new = names;
  496.     np = names;
  497.     np = np->n_flink;
  498.     if (np != NIL)
  499.         np->n_blink = NIL;
  500.     new->n_flink = NIL;
  501.     while (np != NIL) {
  502.         t = new;
  503.         while (strcasecmp(t->n_name, np->n_name) < 0) {
  504.             if (t->n_flink == NIL)
  505.                 break;
  506.             t = t->n_flink;
  507.         }
  508.  
  509.         /*
  510.          * If we ran out of t's, put the new entry after
  511.          * the current value of t.
  512.          */
  513.  
  514.         if (strcasecmp(t->n_name, np->n_name) < 0) {
  515.             t->n_flink = np;
  516.             np->n_blink = t;
  517.             t = np;
  518.             np = np->n_flink;
  519.             t->n_flink = NIL;
  520.             continue;
  521.         }
  522.  
  523.         /*
  524.          * Otherwise, put the new entry in front of the
  525.          * current t.  If at the front of the list,
  526.          * the new guy becomes the new head of the list.
  527.          */
  528.  
  529.         if (t == new) {
  530.             t = np;
  531.             np = np->n_flink;
  532.             t->n_flink = new;
  533.             new->n_blink = t;
  534.             t->n_blink = NIL;
  535.             new = t;
  536.             continue;
  537.         }
  538.  
  539.         /*
  540.          * The normal case -- we are inserting into the
  541.          * middle of the list.
  542.          */
  543.  
  544.         x = np;
  545.         np = np->n_flink;
  546.         x->n_flink = t;
  547.         x->n_blink = t->n_blink;
  548.         t->n_blink->n_flink = x;
  549.         t->n_blink = x;
  550.     }
  551.  
  552.     /*
  553.      * Now the list headed up by new is sorted.
  554.      * Go through it and remove duplicates.
  555.      */
  556.  
  557.     np = new;
  558.     while (np != NIL) {
  559.         t = np;
  560.         while (t->n_flink != NIL &&
  561.                strcasecmp(np->n_name, t->n_flink->n_name) == 0)
  562.             t = t->n_flink;
  563.         if (t == np || t == NIL) {
  564.             np = np->n_flink;
  565.             continue;
  566.         }
  567.         
  568.         /*
  569.          * Now t points to the last entry with the same name
  570.          * as np.  Make np point beyond t.
  571.          */
  572.  
  573.         np->n_flink = t->n_flink;
  574.         if (t->n_flink != NIL)
  575.             t->n_flink->n_blink = np;
  576.         np = np->n_flink;
  577.     }
  578.     return(new);
  579. }
  580.  
  581. /*
  582.  * Put another node onto a list of names and return
  583.  * the list.
  584.  */
  585. struct name *
  586. put(list, node)
  587.     struct name *list, *node;
  588. {
  589.     node->n_flink = list;
  590.     node->n_blink = NIL;
  591.     if (list != NIL)
  592.         list->n_blink = node;
  593.     return(node);
  594. }
  595.  
  596. /*
  597.  * Determine the number of undeleted elements in
  598.  * a name list and return it.
  599.  */
  600. count(np)
  601.     register struct name *np;
  602. {
  603.     register int c;
  604.  
  605.     for (c = 0; np != NIL; np = np->n_flink)
  606.         if ((np->n_type & GDEL) == 0)
  607.             c++;
  608.     return c;
  609. }
  610.  
  611. /*
  612.  * Delete the given name from a namelist.
  613.  */
  614. struct name *
  615. delname(np, name)
  616.     register struct name *np;
  617.     char name[];
  618. {
  619.     register struct name *p;
  620.  
  621.     for (p = np; p != NIL; p = p->n_flink)
  622.         if (strcasecmp(p->n_name, name) == 0) {
  623.             if (p->n_blink == NIL) {
  624.                 if (p->n_flink != NIL)
  625.                     p->n_flink->n_blink = NIL;
  626.                 np = p->n_flink;
  627.                 continue;
  628.             }
  629.             if (p->n_flink == NIL) {
  630.                 if (p->n_blink != NIL)
  631.                     p->n_blink->n_flink = NIL;
  632.                 continue;
  633.             }
  634.             p->n_blink->n_flink = p->n_flink;
  635.             p->n_flink->n_blink = p->n_blink;
  636.         }
  637.     return np;
  638. }
  639.  
  640. /*
  641.  * Pretty print a name list
  642.  * Uncomment it if you need it.
  643.  */
  644.  
  645. /*
  646. prettyprint(name)
  647.     struct name *name;
  648. {
  649.     register struct name *np;
  650.  
  651.     np = name;
  652.     while (np != NIL) {
  653.         fprintf(stderr, "%s(%d) ", np->n_name, np->n_type);
  654.         np = np->n_flink;
  655.     }
  656.     fprintf(stderr, "\n");
  657. }
  658. */
  659.